import { createElement } from 'react'
import dynamic from 'dva/dynamic'
import { isUrl } from './utils/utils'

/**
 * 菜单及其组件配置
 * @type {*[]}
 */
const menuData = [
  {
    name: 'Home',
    path: 'home',
    icon: 'home',
    children: [
      {
        name: 'Index',
        path: 'index',
        icon: 'star',
        component: () => import('./routes/Home'),
      },
    ],
  },
  {
    name: 'System',
    path: 'system',
    children: [
      {
        name: 'User',
        path: 'users',
        component: () => import('./routes/System/User'),
      },
      {
        name: 'About',
        path: 'about',
        component: () => import('./routes/System/About'),
      },
      {
        name: '404',
        path: '/404',
        component: () => import('components/Exception/404'),
      },
    ],
  },
]

/**
 * 除了菜单项之外的路由及其组件配置
 * isAlone: 是否为单独页面, 不使用布局, 默认不需要设置
 * @type {Array}
 */
const routeComponentData = [
  { path: '/login', models: ['login'], component: () => import('components/Login'), isAlone: true },
  { path: '/', models: ['menu'], component: () => import('components/Layout/BasicLayout'), isAlone: true },
]

// 路由配置缓存数据
let routerDataCache

/**
 * 格式化Menu的url路径,
 * @param data
 * @param parentPath
 * @param parentAuthority
 * @returns {*}
 */
function pathFormatter(data, parentPath = '/', parentAuthority) {
  return data.map(item => {
    let { path } = item
    if (!isUrl(path)) {
      path = parentPath + item.path
    }
    const result = {
      ...item,
      path,
      authority: item.authority || parentAuthority,
    }
    if (item.children) {
      result.children = pathFormatter(item.children, `${parentPath}${item.path}/`, item.authority)
    }
    return result
  })
}

/**
 * 获取扁平化的Menu组件数组
 * @param menus
 * @param routerData
 * @returns {*}
 */
const getMenuComponentData = (menus, routerData) => {
  menus.forEach(item => {
    if (item.children) {
      getMenuComponentData(item.children, routerData)
    } else if (item.component) {
      routerData.push(item)
    }
  })
  return routerData
}

/**
 * 判断当前model是否加载到dva app中
 * @param app     dva的app实例
 * @param model   dva的model
 */
const modelNotExisted = (app, model) => {
  // eslint-disable-next-line
  return !app._models.some(({namespace}) => {
    return namespace === model.substring(model.lastIndexOf('/') + 1)
  })
}

// wrapper of dynamic
const dynamicWrapper = (app, models, component) => {
  // register models
  models.forEach(model => {
    if (modelNotExisted(app, model)) {
      // eslint-disable-next-line
      app.model(require(`./models/${model}`).default);
    }
  })

  // () => require('module')
  // transformed by babel-plugin-dynamic-import-node-sync
  if (component.toString().indexOf('.then(') < 0) {
    return props => {
      if (!routerDataCache) {
        routerDataCache = getRouterData(app)
      }
      return createElement(component().default, {
        ...props,
        routerData: routerDataCache,
      })
    }
  }
  // () => import('module')
  return dynamic({
    app,
    models: () =>
      models.filter(model => modelNotExisted(app, model)).map(m => import(`./models/${m}.js`)),
    // add routerData prop
    component: () => {
      if (!routerDataCache) {
        routerDataCache = getRouterData(app)
      }
      return component().then(raw => {
        const Component = raw.default || raw
        return props =>
          createElement(Component, {
            ...props,
            routerData: routerDataCache,
          })
      })
    },
  })
}

/**
 * 获取路由数据
 * @param app dva的app实例
 */
export const getRouterData = app => {
  const routerData = {}
  // 菜单项组件
  const menuComponentData = getMenuComponentData(pathFormatter(menuData), [])
  menuComponentData.forEach(item => {
    routerData[item.path] = {
      component: dynamicWrapper(app, item.models ? item.models : [], item.component),
    }
  })
  // 其他路由及组件
  routeComponentData.forEach(item => {
    routerData[item.path] = {
      component: dynamicWrapper(app, item.models ? item.models : [], item.component),
      isAlone: item.isAlone,
    }
  })
  return routerData
}

/**
 * 获取菜单路由数据
 * @param routerData route组件数据
 */
export const getMenuRouteArr = routerData => {
  const menuRouteArr = []
  Object.keys(routerData).forEach(item => {
    menuRouteArr.push({ path: item, component: routerData[item].component, isAlone: routerData[item].isAlone })
  })
  return menuRouteArr
}

export const getMenuData = (routerData) => {
  const getMenuDataHelper = (menuArr, routerData) => {
    menuArr.forEach(menu => {
      if (routerData[menu.path]) {
        menu.component = routerData[menu.path].component
      }
      if (menu.children) {
        getMenuDataHelper(menu.children, routerData)
      }
    })
  }

  const result = pathFormatter(menuData)
  getMenuDataHelper(result, routerData)
  return result
}
